               // Device header
#include "USART.h"
#include "I2C_Init.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

void ReceiveAndAddCmd(void);
void queueDel( void);
int gorun(int a);
int stoprun(int a);
int OperatingSampleInterval (int a);
int GeneranlSetupDateTime(int a);
int CmdLineProcess(char *pcCmdLine);
char queueAdd( char *pBuff);

#define bool    _Bool
#define false   0
#define true    1
#define CMDLINE_TOO_MANY_ARGS   (-2)
#define CMDLINE_BAD_CMD         (-1)
	int SamMode;//采样模式标志
	int Goflag;             //设备开始运行标志
	int stopflag;           //设备停止运行标志
	uint8_t ucTemp;
	uint32_t Rxflag;
	uint8_t ucaRxBuf[30];
	uint16_t usRxCount=0; 
	unsigned int inter,count=0;
	char GetWhat[30];                       //收到命令部分
	char Getnumber[16];                     //收到数据部分
	int GETbitcount;                        //收到命令部分字节数计数
	int GETbitcountn;                       //收到数字部分字节数计数
	char  Fushu; 
static	float atf = 7;                              //由上位机发送的ASCII码转换来的浮点数
	int queueLen=0;                           //当前命令队列长度
	int AfterEquaFlag;                      //"="后数据标志位
	int GETbitcountDate;                    //收到日期部分字节数计数
	int EquaFlag=0;                         //是否收到"="的标志位
	char Getnumber_DaFlash[10];             //收到时间和Flash部分(专为设定日期及Flash上传设置服务)
	char cmdbuf[100];              //命令缓冲区
	int xMode=0;            //运行模式中间暂存
	int Mode2Interval;                      //间隔设置完成标志
	int tSamptoSamp;                        //传输间隔
	char   ParameterDisplay[15];            //上位机参数显示数组

 long long Month_Day_Year_Hour_Min_Sce;         //接收到的年月日
 long long SetDate0;                            //设置日期年月日
 int Msg_Year;                                  //写入的年
 int Msg_Mon;                                   //写入的月
 int Msg_Day;                                   //写入的日
 int Msg_Hour;                                  //写入的时
 int Msg_Mini;                                  //写入的分
 int Msg_Sec;                                   //写入的秒
	
	
static void NVIC_Configuration(void)
 {
 NVIC_InitTypeDef NVIC_InitStructure;
 
 /* 嵌套向量中断控制器组选择 */

 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
 
 /* 配置 USART 为中断源 */
 NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
 /* 抢断优先级为 1 */
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
 /* 子优先级为 1 */
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
 /* 使能中断 */
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 /* 初始化配置 NVIC */
 NVIC_Init(&NVIC_InitStructure);
 }
 
 void Debug_USART_Config(void)
 {
 GPIO_InitTypeDef GPIO_InitStructure;
 USART_InitTypeDef USART_InitStructure;
 /* 使能 USART GPIO 时钟 */
 RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK |
 DEBUG_USART_TX_GPIO_CLK,
 ENABLE);
 
 /* 使能 USART 时钟 */
 RCC_APB1PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
 
 /* 连接 PXx 到 USARTx_Tx*/
 GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,
 DEBUG_USART_RX_SOURCE,
 DEBUG_USART_RX_AF);
 
 /* 连接 PXx 到 USARTx__Rx*/
 GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,
 DEBUG_USART_TX_SOURCE,
 DEBUG_USART_TX_AF);
 
 /* GPIO 初始化 */
 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 
 /* 配置 Tx 引脚为复用功能 */
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN ;
 GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
 
 /* 配置 Rx 引脚为复用功能 */
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
 GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
 
 /* 配置串 DEBUG_USART 模式 */
 /* 波特率设置：DEBUG_USART_BAUDRATE */
 USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
 /* 字长(数据位+校验位)：8 */
 USART_InitStructure.USART_WordLength = USART_WordLength_8b;
 /* 停止位：1 个停止位 */
 USART_InitStructure.USART_StopBits = USART_StopBits_1;
 /* 校验位选择：不使用校验 */
 USART_InitStructure.USART_Parity = USART_Parity_No;
 /* 硬件流控制：不使用硬件流 */
 USART_InitStructure.USART_HardwareFlowControl =
 USART_HardwareFlowControl_None;
 /* USART 模式控制：同时使能接收和发送 */
 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
 /* 完成 USART 初始化配置 */
 USART_Init(DEBUG_USART, &USART_InitStructure);
 
 /* 嵌套向量中断控制器 NVIC 配置 */
 NVIC_Configuration();
 
 /* 使能串口接收中断 */
 USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE);
 
 /* 使能串口 */
 USART_Cmd(DEBUG_USART, ENABLE);
 }
 
 void USART_INIT(void)
 {
	 Debug_USART_Config();
 }
 
/*****************  发送一个字符 **********************/
 void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch )
{
	/* 发送一个字节数据到USART1 */
	USART_SendData(pUSARTx,ch);
		
	/* 等待发送完毕 */
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}
/*****************  指定长度的发送字符串 **********************/
void Usart_SendStr_length( USART_TypeDef * pUSARTx, uint8_t *str,uint32_t strlen )
{
	unsigned int k=0;
    do 
    {
        Usart_SendByte( pUSARTx, *(str + k) );
        k++;
    } while(k < strlen);
}

/*****************  发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
	unsigned int k=0;
    do 
    {
        Usart_SendByte( pUSARTx, *(str + k) );
        k++;
    } while(*(str + k)!='\0');
}

///重定向c库函数printf到串口RS232_USART，重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到串口RS232_USART */
		USART_SendData(DEBUG_USART, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

///重定向c库函数scanf到串口RS232_USART，重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(DEBUG_USART);
}



//void DEBUG_USART_IRQHandler(void)
//{
//	if(USART_GetITStatus( DEBUG_USART, USART_IT_RXNE ) != RESET)
//	{		
//	  Rxflag=1;		
//		ucTemp = USART_ReceiveData( DEBUG_USART );
//	} 
//	

// 
//		/* 
//			接收DEBUG_USART口的数据，分析并处理 
//			可以将此段代码封装为一个函数，在主程序其它流程调用
//		*/
//		if(Rxflag)
//		{
//			if (usRxCount < sizeof(ucaRxBuf))
//			{
//				ucaRxBuf[usRxCount++] = ucTemp;
//			}
//			else
//			{
//				usRxCount = 0;
//			}
//		
//			/* 简单的通信协议，遇到回车换行符认为1个命令帧，可自行加其它判断实现自定义命令 */
//			/* 遇到换行字符，认为接收到一个命令 */
//			if (ucTemp == 0x0A)	//判断是否是回车
//			{		
//				
//				usRxCount = 0;
//				 while(ucaRxBuf[inter]!='\r'/* inter < (count-2)*/)                    //当检测到回车时
//				{
//					 ReceiveAndAddCmd();                    //进行命令解析
//					 inter++;
//				}					 
//					queueAdd((char*)GetWhat);                  //接受命令				 
//					inter=0;
//					memset(cmdbuf,0,sizeof(cmdbuf));           //清空命令缓冲区
//					
//			}	
//			
//			Rxflag=0;
//		
//		}
//	}	

void ReceiveAndAddCmd(void)
{
        if(('A'<=cmdbuf[inter]&&cmdbuf[inter]<='Z')||('a'<=cmdbuf[inter]&&cmdbuf[inter]<='z'))
        {
            GetWhat[GETbitcount++] = cmdbuf[inter];
        }
        if(('0'<=cmdbuf[inter]&&cmdbuf[inter]<='9')||(cmdbuf[inter]=='.'))
        {
            Getnumber[GETbitcountn++] = cmdbuf[inter];
        }
        switch(cmdbuf[inter])
        {
        case '=':
            GetWhat[GETbitcount++] = cmdbuf[inter];
            break;
        case ',':
            break;
        case '-':
            Fushu=1;
            break;
        }
    GetWhat[GETbitcount]='\0';
    Getnumber[GETbitcountn]='\0';
    atf=atof(Getnumber);
}

/***********************************
 * 队列的单节结构静态
 * *********************************/
struct cmdSingle
{
    char pBuff[30];
    struct cmdSingle *pNext;
};
struct cmdSingle *queueHead,cm1,cm2,cm3;

/***********************************
 *将命令添加到命令队列.
 * *********************************/
char queueAdd( char *pBuff)
{
    /// struct cmdSingle *queueHeadTmpt,*queueRearTmpt;
    /*如果队列中还没有元素，当前添加的元素同时位于对头和队尾*/
    if(queueLen == 0)
    {
        strcpy(cm1.pBuff, pBuff);
        CmdLineProcess(cm1.pBuff);
        queueLen++;
    }
    else if(queueLen == 1)
    {
         strcpy(cm2.pBuff, pBuff);
         CmdLineProcess(cm2.pBuff);
         queueLen++;
    }
    else if(queueLen == 2)
    {
         strcpy(cm3.pBuff, pBuff);
         CmdLineProcess(cm3.pBuff);
         queueLen = 0;
    }
        return(queueLen);
}
#ifndef CMDLINE_MAX_ARGS
#define CMDLINE_MAX_ARGS        8               //定义可以解析的参数最大数量
#endif


    typedef int (*pfnCmdLine)(int argc);

    typedef struct 
    {
        const char *pcCmd;  //指向命令字符串
        pfnCmdLine pfnCmd;  //指向命令函数
    }tCmdLineEntry;
tCmdLineEntry g_sCmdTable[5];//应用程序列表，必须要有，才可以调用函数
     //int CmdLineProcess(char *pcCmdLine);//命令处理函数声明


static char *g_ppcArgv[CMDLINE_MAX_ARGS + 1];   //用来存储指针的命令行参数数组
		
		
int CmdLineProcess(char *pcCmdLine)
{
    char *pcChar;                               //指向命令字符串的指针
    uint_fast8_t ui8Argc;                       //计数器
    bool bFindArg = true;
    tCmdLineEntry *psCmdEntry;                  //定义一个结构体指针，包含命令字符串和命令函数两个成员变量


    //初始化计数器，并且指向命令字符串的开始
    ui8Argc = 0;
    pcChar = pcCmdLine;

    //通过逐个推进，直到在命令行找到一个0字符
    while(*pcChar)
    {
        //如果有空格，用0代替，并设置向下继续查找的标志。
        if(*pcChar == ' ')
        {
            *pcChar = 0;
            bFindArg = true;
        }

        //反之，没有空格，必须是声明中的某一个字符
        else
        {
            //如果bFindArg置位，说明进行查找下一个字符
            if(bFindArg)
            {
                //只要没有到达声明命令的最长处，将指针存储并增加args,argc的计数
                if(ui8Argc < CMDLINE_MAX_ARGS)// 计数个数<8
                {
                    g_ppcArgv[ui8Argc] = pcChar;
                    ui8Argc++;
                    bFindArg = false;
                }

                // 如果命令声明过长，报错
                else
                {
                    return(CMDLINE_TOO_MANY_ARGS);
                }
            }
        }

        //指向命令行里的下一个字符
        pcChar++;
    }

    //如果1个或多个命令被找到，调用并执行此命令
    if(ui8Argc)
    {
        //在命令表的开始处寻找相匹配的命令
        psCmdEntry = &g_sCmdTable[0];
        //在命令向量表里寻找，直到空命令字符串被找到，这是向量表的最后。意味着向量表最后一个必须为0
        while(psCmdEntry->pcCmd)           //pcCmd是结构体指针里的命令字符串变量
        {
            //对比字符，执行命令
            if(!strcmp(g_ppcArgv[0], psCmdEntry->pcCmd))//把上位机发送的字符串与结构体变量相比较
            {
                return(psCmdEntry->pfnCmd(ui8Argc));
            }
            //没有匹配到，则向前查找下一个
                psCmdEntry++;
        }
    }
    queueDel();
    Usart_SendString( DEBUG_USART, (char *)"Command Error\n");
    Usart_SendString( DEBUG_USART, (char *)"Not Executed\r\n");
    //没有匹配到则返回错误
    return(CMDLINE_BAD_CMD);

    //return 1;

}

tCmdLineEntry g_sCmdTable[5] =
{

        {"Go",                  gorun},                     //设备启动
        {"Stop",                stoprun},                   //设备停止
        {"SampleInterval=",     OperatingSampleInterval},   //设置时间间隔
        {"DateTime=",           GeneranlSetupDateTime},     //设置当前时间
        { NULL, NULL }
};


/***********************************
 *队列删除，执行完一个函数调用一次
 * *********************************/
void queueDel( void)
{
    strcpy(cm1.pBuff, "\0");
    queueLen--;
    if(queueLen<0)
    queueLen=0;

    AfterEquaFlag=0;
    EquaFlag=0;
    GETbitcountn=0;
    GETbitcountDate=0;
    GETbitcount=0;
    memset(Getnumber,0x00,16);                  //接收数据清零
    memset(GetWhat,0x00,30);                    //接收命令清零
    memset(Getnumber_DaFlash,0x00,10);
    Fushu=0;
}

int gorun(int a)
{
   Goflag = 1;                  //启动标志置位
   stopflag = 0;                //停止标志复位
   if(Mode2Interval==1)     //在模式二时，当设置完时间间隔
   {
       xMode=2;
       Usart_SendString(DEBUG_USART,"Go\r\n");
       SecondAlarm();       //秒中断设置
   }
   else
   {
       queueDel();
       Usart_SendString(DEBUG_USART,"Time is not configured!");
       Usart_SendString(DEBUG_USART,"<Not Executed>\r\n");
   }
   queueDel();
   return(0);
}

int stoprun(int a)
{
       stopflag = 1;
       Goflag = 0;
       Usart_SendString(DEBUG_USART,"Stop\r\n");
       I2C_single_byte_write(0x0e, 0x00); // 控制寄存器0eh，方波输出频率为1Hz(可改), 关闭秒闹钟
       delay_us(100);
       queueDel();
       //SamMode = 0;
       xMode = 0;
        return(0);
}
//*****************************************************************************
// 采样模式设置指令
//*****************************************************************************
int OperatingSampleMode(int a)
{
    if(xMode==0)
{
  SamMode=atoi(Getnumber);
  switch(SamMode)
  {
  case 1:
      Usart_SendString(DEBUG_USART,"SampleMode=1\r\n");
      //StoreMode=0x01;
      I2C_single_byte_write(0x0e, 0x00); // 控制寄存器0eh，方波输出频率为1Hz(可改), 关闭秒闹钟
      delay_us(100);
      queueDel();
      break;
  case 2:
      queueDel();
      Usart_SendString(DEBUG_USART,"SampleMode=2\r\n");
      //SecondAlarm();                    // 设置秒闹钟
      //delay_ms(1000);
      //StoreMode=0x02;
      break;
  case 3:
      queueDel();
      Usart_SendString(DEBUG_USART,"SampleMode=3\r\n");
      //StoreMode=0x03;
      I2C_single_byte_write(0x0e, 0x00); // 控制寄存器0eh，方波输出频率为1Hz(可改), 关闭秒闹钟
      delay_us(100);
      break;
  }
}
    return(0);
}
//*****************************************************************************
// 采样间隔设置指令，输入范围6-21600s,先要设置为模式2，才可以继续设置，否则报错
//输入
//*****************************************************************************

int OperatingSampleInterval (int a)
{
    Usart_SendString(DEBUG_USART,"\r\nSampleInterval Set\r\n");
        if(SamMode==2)                              //当工作模式为模式二时
        {
			 
            tSamptoSamp=(int )atf;
			
            if((5<tSamptoSamp)&&(tSamptoSamp<21601))//6-21600s间隔
            {
				//ltoa((long )tSamptoSamp,ParameterDisplay,10);
				
                sprintf(ParameterDisplay, "%d",tSamptoSamp );
				
                Usart_SendString(DEBUG_USART,"SampleInterval= ");     //串口发送采样时间间隔提示
                Usart_SendString(DEBUG_USART,ParameterDisplay);       //串口发送上位机输入的时间间隔
                Usart_SendString(DEBUG_USART,"s\r\n");
                /***********************/
                Usart_SendString(DEBUG_USART,"<Executed>\r\n");
                queueDel();     //删除时间间隔命令队列
                Mode2Interval=1;//模式二标志置位
            }
            else
            {
                Usart_SendString(DEBUG_USART,"Range Error\r\n");
                Usart_SendString(DEBUG_USART,"<Not Executed>\r\n");
                queueDel();
            }
        }
        else
        {
            Usart_SendString(DEBUG_USART,"Please Set Mode Or Check Mode=2 First!\r\n");
            Usart_SendString(DEBUG_USART,"<Not Executed>\r\n");
            queueDel();
        }

        return(24);
}

/***********************************
 * 设置下位机系统时间
 * *********************************/
int GeneranlSetupDateTime(int a)
{

    Month_Day_Year_Hour_Min_Sce=atoll(Getnumber);    //将从PC接收到的数据转换成整数，赋给专门的上传数据的参数。
    /***************************将接收到的时间依次转换成对应的BCD码********************************************************/
    Msg_Sec =((Month_Day_Year_Hour_Min_Sce%10)&0xff)|((((Month_Day_Year_Hour_Min_Sce/10)%10)&0XFF)<<4);
    Msg_Mini =((((Month_Day_Year_Hour_Min_Sce/100)%10)&0XFF))|((((Month_Day_Year_Hour_Min_Sce/1000)%10)&0XFF)<<4);
    Msg_Hour =(((Month_Day_Year_Hour_Min_Sce/10000)%10)&0xff)|((((Month_Day_Year_Hour_Min_Sce/100000)%10)&0XFF)<<4);
    Msg_Day =(((Month_Day_Year_Hour_Min_Sce/1000000)%10)&0xff)|((((Month_Day_Year_Hour_Min_Sce/10000000)%10)&0XFF)<<4);
    Msg_Mon  =(((Month_Day_Year_Hour_Min_Sce/100000000)%10)&0xff)|((((Month_Day_Year_Hour_Min_Sce/1000000000)%10)&0XFF)<<4);
    Msg_Year  =(((Month_Day_Year_Hour_Min_Sce/10000000000)%10)&0xff)|((((Month_Day_Year_Hour_Min_Sce/100000000000)%10)&0XFF)<<4);

    /****配置以进入秒中断***这个SetTime似乎需要一些判断条件，上电读取时间，或者有个默认的出厂时间？？？*/
    //设置时间
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    GPIO_InitTypeDef GPIO_InitStruct;
    // 2. 初始化GPIO结构体
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;      // 输入模式
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;    // 推挽输出
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;  // 输出速度
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;   // 不设置上拉/下拉
    // 3. 初始化GPIOF的PF0引脚
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    GPIO_ResetBits(GPIOA,3);
    delay_ms(500);
    GPIO_SetBits(GPIOA,3);
    delay_us(20);
    I2C_EE_Init();
    DS3231_Init();
    delay_us(20);
    //Set_RTC();
    I2C_single_byte_write(0x06, Msg_Year);      //设置年
    delay_us(200);
    I2C_single_byte_write(0x05, Msg_Mon);       //设置月
    delay_us(200);
    I2C_single_byte_write(0x04, Msg_Day);       //设置日
    delay_us(200);
    I2C_single_byte_write(0x02, Msg_Hour);      //设置时
    delay_us(200);
    I2C_single_byte_write(0x01, Msg_Mini);      //设置分
    delay_us(200);
    I2C_single_byte_write(0x00, Msg_Sec);       //设置秒
    delay_us(200);

    Usart_SendString(DEBUG_USART,"<DateTime Set!>\r\n");  //串口发送设置时间提示
    Usart_SendString(DEBUG_USART,"<DateTime= ");          //串口发送设置时间
    Usart_SendString(DEBUG_USART,Getnumber);              //发送上位机输入的时间格式
    Usart_SendString(DEBUG_USART,">\r\n");
    queueDel();             //删除命令队列中的时间设置相关命令
    return 1;
}

